//package hasthi.container;
///*
// * Based on sample message
// */
//import hasthi.common.BaseContext;
//import hasthi.common.ErrorManager;
//import hasthi.common.HasthiError;
//import hasthi.common.HasthiException;
//import hasthi.common.RemoteProcessorException;
//import hasthi.common.XmlBeanUtils;
//import hasthi.common.HasthiException.FaultCode;
//import hasthi.common.constants.HasthiConstants;
//
//import java.io.ByteArrayInputStream;
//import java.io.ByteArrayOutputStream;
//import java.io.File;
//import java.io.IOException;
//import java.io.InputStream;
//import java.io.OutputStream;
//import java.io.PrintWriter;
//import java.net.InetAddress;
//import java.net.InetSocketAddress;
//import java.net.SocketAddress;
//import java.net.UnknownHostException;
//import java.security.GeneralSecurityException;
//import java.security.cert.X509Certificate;
//import java.util.Map;
//
//import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;
//import org.apache.http.Header;
//import org.apache.http.HttpEntity;
//import org.apache.http.HttpEntityEnclosingRequest;
//import org.apache.http.HttpException;
//import org.apache.http.HttpRequest;
//import org.apache.http.HttpResponse;
//import org.apache.http.HttpStatus;
//import org.apache.http.MethodNotSupportedException;
//import org.apache.http.impl.DefaultConnectionReuseStrategy;
//import org.apache.http.impl.DefaultHttpResponseFactory;
//import org.apache.http.impl.nio.DefaultServerIOEventDispatch;
//import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor;
//import org.apache.http.message.BasicHeader;
//import org.apache.http.nio.NHttpConnection;
//import org.apache.http.nio.entity.FileNIOEntity;
//import org.apache.http.nio.protocol.BufferingHttpServiceHandler;
//import org.apache.http.nio.protocol.EventListener;
//import org.apache.http.nio.reactor.IOEventDispatch;
//import org.apache.http.nio.reactor.IOReactorException;
//import org.apache.http.nio.reactor.ListenerEndpoint;
//import org.apache.http.nio.reactor.ListeningIOReactor;
//import org.apache.http.params.BasicHttpParams;
//import org.apache.http.params.CoreConnectionPNames;
//import org.apache.http.params.CoreProtocolPNames;
//import org.apache.http.params.HttpParams;
//import org.apache.http.protocol.BasicHttpProcessor;
//import org.apache.http.protocol.HTTP;
//import org.apache.http.protocol.HttpContext;
//import org.apache.http.protocol.HttpRequestHandler;
//import org.apache.http.protocol.HttpRequestHandlerRegistry;
//import org.apache.http.protocol.ResponseConnControl;
//import org.apache.http.protocol.ResponseContent;
//import org.apache.http.protocol.ResponseDate;
//import org.apache.http.protocol.ResponseServer;
//import org.apache.xmlbeans.XmlObject;
//import org.globus.gsi.CertUtil;
//import org.ietf.jgss.GSSCredential;
//import org.xmlpull.v1.builder.XmlBuilderException;
//import org.xmlpull.v1.builder.XmlDocument;
//import org.xmlpull.v1.builder.XmlElement;
//import org.xmlpull.v1.builder.XmlInfosetBuilder;
//
//import xsul.XmlConstants;
//import xsul.XsulException;
//import xsul.invoker.gsi.GsiInvoker;
//import xsul.invoker.puretls.PuretlsInvoker;
//import xsul.invoker.soap_over_http.SoapHttpDynamicInfosetInvoker;
//import xsul.soap.SoapUtil;
//import xsul.soap12_util.Soap12Util;
//import xsul.xbeans_util.XBeansUtil;
//
//public class NonBlockingSoapContainer implements HttpRequestHandler, UnicastContianier{
//    private static XmlInfosetBuilder builder = XmlConstants.BUILDER;
//    private static Log log = LogFactory.getLog(HasthiConstants.LOGGER_NAME);
//
//    private final MessageProcessor messageProcessor;
//    private final BaseContext baseContext;
//    private ListeningIOReactor ioReactor;
//    private String containerAddress; 
//    private NHttpClient httpClient;
//    private int port = 0;
//
//    public NonBlockingSoapContainer(BaseContext baseContext, MessageProcessor messageProcessor) throws HasthiException {
//        this(baseContext,messageProcessor,0);
//    }
//    
//    public NonBlockingSoapContainer(BaseContext baseContext, MessageProcessor messageProcessor,int port) throws HasthiException {
//        this.messageProcessor = messageProcessor;
//        this.baseContext = baseContext;
//        httpClient = new NHttpClient();
//        httpClient.start();
//        this.port = port;
//    }
//
//    public void startContainer() throws HasthiException {
//        try {
//            //NHttpServiceHandler
//            HttpParams params = new BasicHttpParams();
//            params
//                .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000)
//                .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
//                .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
//                .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
//                .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1");
//
//            BasicHttpProcessor httpproc = new BasicHttpProcessor();
//            httpproc.addInterceptor(new ResponseDate());
//            httpproc.addInterceptor(new ResponseServer());
//            httpproc.addInterceptor(new ResponseContent());
//            httpproc.addInterceptor(new ResponseConnControl());
//
//            
////            BufferingHttpServiceHandler handler = new BufferingHttpServiceHandler(
////                    httpproc,
////                    new DefaultHttpResponseFactory(),
////                    new DefaultConnectionReuseStrategy(),
////                    params);
//            BufferingHttpServiceHandler handler = new BufferingHttpServiceHandler(
//                    httpproc,
//                    new DefaultHttpResponseFactory(),
//                    new DefaultConnectionReuseStrategy(),
//                    //new NoConnectionReuseStrategy(),
//                    params);
//
//            // Set up request handlers
//            HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry();
//            reqistry.register("*", this);
//
//            handler.setHandlerResolver(reqistry);
//
//            // Provide an event logger
//            handler.setEventListener(new EventLogger());
//            
////            IOEventDispatch ioEventDispatch = new SSLServerIOEventDispatch(
////                    handler, 
////                    sslcontext,
////                    params);
//
//            final IOEventDispatch ioEventDispatch = new DefaultServerIOEventDispatch(handler, params);
//            ioReactor = new DefaultListeningIOReactor(2, params);
//            ioReactor.listen(new InetSocketAddress(port));
//            
//            Thread t = new Thread(new Runnable() {
//                public void run() {
//                    try {
//                        ioReactor.execute(ioEventDispatch);
//                    } catch (Exception e) {
//                        log.error("Failed to start server",e);
//                        ErrorManager.error(e);
//                    }
//                }
//            });
//            t.start();
//            
//            while(ioReactor.getEndpoints().size() == 0){
//                Thread.sleep(1000);
//            }
//            for(ListenerEndpoint endpoint:ioReactor.getEndpoints()){
//                SocketAddress address = endpoint.getAddress();
//                if(address instanceof InetSocketAddress && ((InetSocketAddress)address).getPort() != 0){
//                    StringBuffer buffer = new StringBuffer();
//                    buffer.append("http://").append(InetAddress.getLocalHost().getCanonicalHostName())
//                    .append(":").append(((InetSocketAddress)address).getPort()).append("/");
//                    containerAddress = buffer.toString();
//                    break;
//                }else{
//                    throw new HasthiError("Unknown endpoint type");
//                }
//            }
//            if(messageProcessor != null){
//                messageProcessor.addContainer(this);
//            }
//        } catch (IOReactorException e) {
//            throw new HasthiException(e,FaultCode.InitalizationError);
//        } catch (UnknownHostException e) {
//            throw new HasthiException(e,FaultCode.InitalizationError);
//        } catch (InterruptedException e) {
//            throw new HasthiException(e,FaultCode.InitalizationError);
//        }
//       
//    }
//    
//    public void stopContainer() throws HasthiException {
//        try {
//            if(ioReactor != null){
//                ioReactor.shutdown();    
//            }
//            httpClient.shutDown();
//        } catch (IOException e) {
//            throw new HasthiException(e,FaultCode.InitalizationError);
//        }
//    }
//    
//    static class EventLogger implements EventListener {
//
//        public void connectionOpen(final NHttpConnection conn) {
//            //System.out.println("Connection open: " + conn);
//        }
//
//        public void connectionTimeout(final NHttpConnection conn) {
//            //System.out.println("Connection timed out: " + conn);
//        }
//
//        public void connectionClosed(final NHttpConnection conn) {
//           // System.out.println("Connection closed: " + conn);
//        }
//
//        public void fatalIOException(final IOException ex, final NHttpConnection conn) {
//            System.err.println("I/O error: " + ex.getMessage());
//            log.error(ex);
//        }
//
//        public void fatalProtocolException(final HttpException ex, final NHttpConnection conn) {
//            System.err.println("HTTP error: " + ex.getMessage());
//            log.error("HTTP Error at HTTP server",ex);
//            ErrorManager.error(ex);
//        }
//
//    }
//
//    public void handle(HttpRequest request, HttpResponse response, HttpContext httpContext) throws HttpException,
//            IOException {
//      try{
//        String method = request.getRequestLine().getMethod().toUpperCase();
//        if (!method.equals("HEAD") && !method.equals("POST")) {
//            throw new MethodNotSupportedException(method + " method not supported");
//        }
//        
//        XmlDocument soapResponse = null;
//        if (method.equals("GET")){
//            String path = request.getRequestLine().getUri();
//            File file2serve = ContainerUtils.findFile2Serve(path);
//            if(file2serve != null){
//                //HttpEntity
//                response.setEntity(new FileNIOEntity(file2serve,"text/html"));
//                return;
//            }
//            //we do  not support foward in nonblocking container
//            String forwardUrl = ContainerUtils.getForwardUrl(path);
//            if(forwardUrl!= null){
//                throw new UnsupportedOperationException();
//            } 
//            MessageContext messageContext = new SimpleMessageContext(null,request.getRequestLine().getUri(),"");
//            XmlObject responseAsXmlbeans = messageProcessor.processMessage(messageContext);
//            if(responseAsXmlbeans != null){
//                XmlElement responseAsXml = XBeansUtil.xmlObjectToXmlElement(responseAsXmlbeans);
//                soapResponse = builder.newDocument();
//                soapResponse.setDocumentElement(responseAsXml);
//            }
//        }else if (request instanceof HttpEntityEnclosingRequest) {
//            SoapUtil soapFragrance = null;
//            try {
//                HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
//                InputStream in = entity.getContent();
//                
//                XmlDocument soapRequest = builder.parseInputStream(in);
//                
//                String path = request.getRequestLine().getUri();
//                //we do  not support foward in nonblocking container
//                String forwardUrl = ContainerUtils.getForwardUrl(path);
//                if(forwardUrl!= null){
//                    throw new UnsupportedOperationException();
//                } 
//                
//                XSULMessageContext reqMessageContext =  new XSULMessageContext(soapRequest,path);
//                soapFragrance = reqMessageContext.getSoapFragrance();
//                XmlObject responseObj = messageProcessor.processMessage(reqMessageContext);
//                if(responseObj != null){
//                    soapResponse = soapFragrance.wrapBodyContent(XBeansUtil.xmlObjectToXmlElement(responseObj));    
//                }else{
//                    soapResponse = null;
//                }
//                
//            } catch (Throwable e) {
//                log.error("Error processing request",e);
//                if(soapFragrance == null){
//                    soapFragrance = Soap12Util.getInstance();
//                }
//                XmlElement faultMessage;
//                if(e instanceof HasthiException){
//                    faultMessage = ((HasthiException)e).createFault(soapFragrance);
//                } else{
//                    faultMessage = soapFragrance.generateSoapServerFault(e.getMessage(), e);
//                }
//                soapResponse = soapFragrance.wrapBodyContent(faultMessage);
//            } 
//            response.setHeader(HTTP.CONTENT_TYPE,"text/xml");
//            if(soapResponse != null){
//                response.setStatusCode(HttpStatus.SC_OK);
//                response.setEntity(new XSULHttpEntity(soapResponse,true));
////                
////                boolean useNative = false;
////                ReadableByteChannel source;
////                WritableByteChannel sink;
////
////                if (useNative) {
////                    Pipe pipe = Pipe.open();
////                    source = pipe.source();
////                    sink = pipe.sink();
////                } else {
////                    PipedOutputStream pipedOut;
////                    PipedInputStream pipedIn = new PipedInputStream();
////                    pipedOut = new PipedOutputStream(pipedIn);
////                    source = Channels.newChannel(pipedIn);
////                    sink = Channels.newChannel(pipedOut);
////                }
////                
////                BasicHttpEntity responseEntity = new BasicHttpEntity();
////                responseEntity.setContent(Channels.newInputStream(source));
//////            if (httpVersion.greaterEquals(HttpVersion.HTTP_1_1)) {
//////                entity.setChunked(true);
//////            }
////                response.setEntity(responseEntity);
////                OutputStream outstream = Channels.newOutputStream(sink); 
////                builder.serializeToOutputStream(soapResponse, outstream);
////                outstream.close();
//            }else{
//                response.setStatusCode(HttpStatus.SC_ACCEPTED);
//            }
//        }
//      }catch(Throwable e){
//          log.error(e);
//          throw new HttpException("Error at HTTP level ",e);
//      }
//    }
//
//    
//    public String getContainierAddress() {
//        return containerAddress;
//    }
//    
//    public CommunicationClient createCommunicationClient() throws HasthiException {
//        return new SOAPCommunicationClient();
//    }
//    
//
//    public class SOAPCommunicationClient implements CommunicationClient{
//        public SOAPCommunicationClient(){
//        }
//        
//        public void send(MessageContext message) throws RemoteProcessorException,HasthiException {
////            try {
////                invoker = createInvoker(message.getAddress().getAddressAsString());
////                XmlElement request = XBeansUtil.xmlObjectToXmlElement(message.getRequest());
////                Soap12Util util = Soap12Util.getInstance();
////                XmlDocument soapRequest = util.wrapBodyContent(request);
////                WsaMessageInformationHeaders headers = new WsaMessageInformationHeaders(soapRequest);
////                headers.setTo(new URI(message.getSoapEndpoint()));
////                headers.setAction(new URI(message.getSoapAction()));
////                headers.setMessageId(new URI(UUID.randomUUID().toString()));
////                invoker.setLocation(message.getSoapEndpoint());
////                invoker.invokeXml(soapRequest);
//                httpClient.sendReceive(message);
////            } catch (URISyntaxException e) {
////                throw new HasthiException(e,FaultCode.ErrorAtClientBeforeWsCall);
////            }catch(DynamicInfosetInvokerException e){
////                throw new HasthiException(e,FaultCode.ErrorAtClientWhileWsCall);
////            }
//        }
//
//        public XmlObject sendReceive(MessageContext message) throws RemoteProcessorException,HasthiException {
//            return httpClient.sendReceive(message);
////            try {
////                invoker = createInvoker(message.getSoapEndpoint());
////                XmlElement request = XBeansUtil.xmlObjectToXmlElement(message.getRequest());
////                
////                SoapUtil util = Soap12Util.getInstance();
////                XmlDocument soapRequest = util.wrapBodyContent(request);
////                WsaMessageInformationHeaders headers = new WsaMessageInformationHeaders(soapRequest);
////                headers.setTo(new URI(message.getSoapEndpoint()));
////                headers.setAction(new URI(message.getSoapAction()));
////                invoker.setLocation(message.getSoapEndpoint());
////
////                //Utils.prettyPrint(soapRequest.getDocumentElement());
////                XmlDocument soapResponse = invoker.invokeXml(soapRequest);
////                //Utils.prettyPrint(soapResponse.getDocumentElement());
////                SoapUtil[] utils = new SoapUtil[]{Soap11Util.getInstance(),
////                        Soap12Util.getInstance()};
////                util = SoapUtil.selectSoapFragrance(soapResponse, utils);
////                XmlElement result = util.requiredBodyContent(soapResponse);
////                XmlObject responseAsXbeans  = XBeansUtil.xmlElementToXmlObject(result);
////                
////                if(SOAPUtils.isFaultMessage(responseAsXbeans)){
////                    throw HasthiException.buildException(responseAsXbeans);
////                }else{
////                    return responseAsXbeans;
////                }
////            } catch (URISyntaxException e) {
////                throw new HasthiException(e,FaultCode.ErrorAtClientBeforeWsCall);
////            }catch(DynamicInfosetInvokerException e){
////                throw new HasthiException(e,FaultCode.ErrorAtClientWhileWsCall);
////            }
//        }
//    }
//    
// 
//    
//    public void send(MessageContext message) throws RemoteProcessorException,HasthiException {
//        SOAPCommunicationClient client = new SOAPCommunicationClient();
//        client.send(message);
//    }
//
//    public XmlObject sendReceive(MessageContext message) throws RemoteProcessorException,HasthiException {
//        SOAPCommunicationClient client = new SOAPCommunicationClient();
//        return client.sendReceive(message);
//    }
//    
//    public static SoapHttpDynamicInfosetInvoker createSecureInvoker(BaseContext context,GSSCredential sessionCredentail) throws HasthiException{
//        try {
//            String trustedCertFile = context.getTrustedCertsFile();
//            String hostKeyfile = context.getHostKeyfile();
//            GSSCredential credential = sessionCredentail;
//            if(credential == null){
//                credential = context.getCredential();   
//            }
//            
//            SoapHttpDynamicInfosetInvoker invoker;
//            if(trustedCertFile != null && hostKeyfile != null){
//                invoker = new PuretlsInvoker(hostKeyfile,"",trustedCertFile);
//            }else if(credential != null){
//                if(context.getTrustedCertsFile() != null){
//                    X509Certificate[] certs = null;
//                    certs = CertUtil.loadCertificates(trustedCertFile);
//                    invoker = new GsiInvoker(credential,certs);
//                }else{
//                    invoker = new GsiInvoker(credential);    
//                }
//            }else{
//                throw new HasthiException("Can not create a secure Invoker, no credentails provided",FaultCode.InitalizationError);
//            }
//            return invoker;
//        } catch (XsulException e) {
//            throw new HasthiException(e,FaultCode.InitalizationError);
//        } catch (IOException e) {
//            throw new HasthiException(e,FaultCode.InitalizationError);
//        } catch (GeneralSecurityException e) {
//            throw new HasthiException(e,FaultCode.InitalizationError);
//        }
//    }
//    
//    public String doRESTCall(String url,Map<String, String> parameters,String method) throws HasthiException{
//        SoapHttpDynamicInfosetInvoker invoker;
//        if(url.startsWith("http")){
//            invoker = createSecureInvoker(baseContext, null);
//        }else{
//            invoker = new SoapHttpDynamicInfosetInvoker();
//        }
//        return invoker.invokeHttpGet(url);
//    }
//
//    
//    public static class XSULHttpEntity implements HttpEntity{
//        private XmlDocument message;
//        //We need to do this only with xsul as a client. Content length -1 means do chunking
//        private byte[] buffer;
//        private boolean chunked; 
//
//        public XSULHttpEntity(XmlDocument message,boolean chunked) {
//            this.chunked = chunked;
//            if(chunked){
//                this.message = message;    
//            }else{
//                try {
//                    ByteArrayOutputStream bufferStream = new ByteArrayOutputStream();
//                    builder.serializeToOutputStream(message, bufferStream);
//                    bufferStream.flush();
//                    buffer = bufferStream.toByteArray();
//                } catch (XmlBuilderException e) {
//                    throw new HasthiError(e);
//                } catch (IOException e) {
//                    throw new HasthiError(e);
//                }
//            }
//        }
//
//        public void consumeContent() throws IOException {
//            this.message = null;
//            buffer = null;
//        }
//
//        public InputStream getContent() throws IOException, IllegalStateException {
//            // TODO Auto-generated method stub
//            return null;
//        }
//
//        public Header getContentEncoding() {
//            return null;
//            //return new BasicHeader(HTTP.CONTENT_ENCODING ,HTTP.UTF_8);
//        }
//
//        public long getContentLength() {
//            if(chunked){
//                return -1;
//            }else{
//                return buffer.length;    
//            }
//        }
//
//        public Header getContentType() {
//            //return new BasicHeader(HTTP.CONTENT_TYPE,"text/xml");
//            return new BasicHeader(HTTP.CONTENT_TYPE,"text/xml;charset=utf-8");
//        }
//
//        public boolean isChunked() {
//            return false;
//        }
//
//        public boolean isRepeatable() {
//            return false;
//        }
//
//        public boolean isStreaming() {
//            return true;
//        }
//
//        public void writeTo(OutputStream outstream) throws IOException {
//            if(chunked){
//                builder.serializeToOutputStream(message, outstream);                
//            }else{
//                outstream.write(buffer);
//                outstream.flush();
//            }
//
//        }
//    }
//    
//}
